package com.gmlive.common.host.manager;

import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.CountDownTimer;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;

import com.gmlive.common.host.BuildConfig;
import com.gmlive.common.host.HostUpdateCallback;
import com.gmlive.common.host.config.Config;
import com.gmlive.common.host.helper.ApiUrlHelper;
import com.gmlive.common.host.retrofit.BaseCallback;
import com.gmlive.common.host.retrofit.HostReqThread;
import com.gmlive.common.host.retrofit.RetrofitCreateHelper;
import com.gmlive.common.host.server.IApi;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import org.jetbrains.annotations.Nullable;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.LinkedHashMap;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.atomic.AtomicLong;

import okhttp3.OkHttpClient;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;


/**
 * Created by ZhongJianXin
 * on 2019-10-17
 * desc
 */
public class HostUpdateManager extends BaseCallback<String> {

    private volatile AtomicLong sUpdateTimeout = new AtomicLong(5000L);

    /**
     * 保存服务器的结果
     */
    private LinkedHashMap<String, String> serverMap = null;
    private CountDownTimer countDownTimer;

    private static final Gson gson = new Gson();
    private Config config;

    @Override
    protected void onSuccess(@Nullable String s) {
        if (BuildConfig.DEBUG) {
            Log.w("HostUpdateManager", " onSuccess");
        }
        if (s != null) {
            JSONObject jsonObject = null;
            try {
                jsonObject = new JSONObject(s);
                setServerMap(jsonObject.optString("data"));
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    protected void onFailed(int code, @Nullable String msg) {
        if (BuildConfig.DEBUG) {
            Log.w("HostUpdateManager", " onFailed");
        }
    }

    private static class SingletonHolder {
        private static final HostUpdateManager INSTANCE = new HostUpdateManager();
    }

    public HostUpdateManager() {
    }

    public static HostUpdateManager ins() {
        return HostUpdateManager.SingletonHolder.INSTANCE;
    }

    private void setConfig(Config config) {
        this.config = config;
    }

    public Builder getBuilder() {
        return new Builder();
    }

    public void getUpdateHost(HostUpdateCallback callback) {
        if (config == null) {
            if (callback != null) {
                callback.onError(new Throwable("请初始化，直接退出"), true);
            }
            Log.e("HostUpdateManager", "config is null，请初始化，直接退出");
            return;
        }
        if (serverMap != null) {
            serverMap = null;
        }
        //先网络请求
        doRequestHost();

        if (BuildConfig.DEBUG) {
            Log.e("HostUpdateManager", "getTimeout start");
        }
        LinkedHashMap<String, String> cacheModel = getHostUpdateItem();
        if (cacheModel == null || cacheModel.isEmpty()) {
            sUpdateTimeout.set(15_000);
        }
        if (BuildConfig.DEBUG) {
            Log.e("HostUpdateManager", "sUpdateTimeout :" + sUpdateTimeout.get());
        }
        if (Looper.myLooper() != Looper.getMainLooper()) {
            Looper.prepare();
        }
        //开始轮询
        if (countDownTimer == null) {
            countDownTimer = new CountDownTimer(5000, 100) {
                @Override
                public void onTick(long millisUntilFinished) {
                    Log.e("HostUpdateManager", "countDownTimer onTick serverMap.size()=" + (serverMap == null ? "null" : serverMap.size()));
                    if (serverMap == null) {
                        return;
                    }
                    ApiUrlHelper.getInstance().setUpHostMap(serverMap);
                    storeHostUpdateItem(serverMap);
                    if (callback != null) {
                        callback.onSuccess();
                    }
                    releaseTimer();

                }

                @Override
                public void onFinish() {
                    Log.e("HostUpdateManager", "countDownTimer onFinish serverMap.size()=" + (serverMap == null ? "null" : serverMap.size()));
                    if (callback == null) {
                        return;
                    }

                    if (serverMap != null && !serverMap.isEmpty()) {
                        callback.onSuccess();
                    } else {
                        //超时后最后挣扎着设置之前缓存的host
                        if (cacheModel != null && !cacheModel.isEmpty()) {
                            ApiUrlHelper.getInstance().setUpHostMap(cacheModel);
                        }
                        callback.onError(new Throwable("网络请求失败或超时，并且没有缓存host信息，直接退出"), cacheModel == null || cacheModel.isEmpty());
                    }
                }
            };
        }
        countDownTimer.cancel();
        countDownTimer.start();
        if (Looper.myLooper() != Looper.getMainLooper()) {
            Looper.loop();
        }
    }

    /**
     * 只负责跑马，请求回来的结果放在一个地方
     */
    private void doRequestHost() {
        if (config == null || config.getIps() == null || config.getIps().length == 0) {
            return;
        }

        int length = config.getIps().length;
        for (int i = 0; i < length; i++) {
            String ip = config.getIps()[i];
            if (config.getThreadPoolExecutor() == null) {
                HostReqThread hostReqThread = new HostReqThread("HostReqThread" + i, ip);
                hostReqThread.start();
            } else {
                config.getThreadPoolExecutor().execute(() -> req(ip));
            }
        }
    }

    private void req(String ip) {
        RetrofitCreateHelper.Companion.createApi2String(ip, IApi.class)
                .requestHostUpdate(ip + getUrl(), getKey())
                .enqueue(this);
    }

    private LinkedHashMap<String, String> parseJson(String jsonStr) {
        if (TextUtils.isEmpty(jsonStr)) {
            return null;
        }
        try {
            LinkedHashMap<String, String> jsonMap = gson.fromJson(jsonStr, new TypeToken<LinkedHashMap<String, String>>() {
            }.getType());
            return jsonMap;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 同步操作
     *
     * @return
     */
    public synchronized boolean setHostFromLocal() {
        LinkedHashMap<String, String> map = getHostUpdateItem();
        if (map != null && !map.isEmpty()) {
            ApiUrlHelper.getInstance().setUpHostMap(map);
        }
        return ApiUrlHelper.getInstance().isHostInit();
    }

    private void storeHostUpdateItem(LinkedHashMap<String, String> map) {
        if (getSharedPreferences() == null) {
            return;
        }
        SharedPreferences.Editor edit = getSharedPreferences().edit();
        if (edit == null) {
            return;
        }
        if (map == null) {
            edit.putString(getSpKey(), "");
        } else {
            ApiUrlHelper.getInstance().setUpHostMap(map);
            edit.putString(getSpKey(), gson.toJson(map));
        }
        edit.apply();
    }

    private LinkedHashMap<String, String> getHostUpdateItem() {
        if (getSharedPreferences() == null) {
            return null;
        }
        String hostInfo = getSharedPreferences().getString(getSpKey(), "");
        if (TextUtils.isEmpty(hostInfo)) {
            return null;
        }
        return parseJson(hostInfo);
    }

    private SharedPreferences getSharedPreferences() {
        if (config == null || config.getContext() == null) {
            return null;
        }
        return config.getContext().getSharedPreferences(getSpKey(), Activity.MODE_PRIVATE);
    }

    private String getSpKey() {
        return "host_info_v2";
    }

    public void setServerMap(String model) {
        Log.w("HostUpdateManager", "----------setServerMap----------");
        if (model == null || TextUtils.isEmpty(model)) {
            return;
        }
        serverMap = parseJson(model);
    }

    public boolean isHostInit() {
        return ApiUrlHelper.getInstance().isHostInit();
    }

    private void releaseTimer() {
        if (countDownTimer != null) {
            Log.d("HostUpdateManager", "----------releaseTimer----------");
            countDownTimer.cancel();
            countDownTimer = null;
        }
    }

    public boolean isTest() {
        return config != null && config.isTest();
    }

    public OkHttpClient getOkHttpClient() {
        if (config == null) {
            return null;
        }
        return config.getOkHttpClient();
    }

    public String getKey() {
        if (config == null) {
            return "";
        }
        return config.getKey();
    }

    public String getUrl() {
        if (config == null) {
            return "";
        }
        return config.getUrl();
    }

    public static class Builder {

        private Context context;

        //服务器ip
        private String[] ips;

        //url
        private String url;

        //请求的key
        private String key;

        //是否测试环境
        private Boolean isTest;

        private OkHttpClient client;

        private ThreadPoolExecutor threadPoolExecutor;

        public Builder setContext(Context context) {
            this.context = context;
            return this;
        }

        public Builder setIps(String... ips) {
            this.ips = ips;
            return this;
        }

        public Builder setUrl(String url) {
            this.url = url;
            return this;
        }

        public Builder setKey(String key) {
            this.key = key;
            return this;
        }

        public Builder setTest(Boolean isTest) {
            this.isTest = isTest;
            return this;
        }

        public Builder setOkHttpClient(OkHttpClient client) {
            this.client = client;
            return this;
        }

        public Builder setThreadPoolExecutor(ThreadPoolExecutor executor) {
            this.threadPoolExecutor = executor;
            return this;
        }

        public void build() {
            HostUpdateManager.ins().setConfig(new Config(context, ips, url, key, isTest, client, threadPoolExecutor));
        }
    }

}
